package eg.backend.base.repository;

import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

public class JpaBaseDao implements BaseDao {
	@PersistenceContext
	protected EntityManager entityManager;
	
	public <T> T save(T domainEntity) {
		return (T) entityManager.merge(domainEntity);
	}
	
	public <T> void delete(T domainEntity) {
		entityManager.remove(domainEntity);
	}

	@SuppressWarnings("unchecked")
	public <T, PK extends Serializable> T get(PK identifier, Class<T> clazz) {
		String ql = "select t from " + clazz.getName() + " t where t.id = :id";
		Query query = entityManager.createQuery(ql);
		query.setParameter("id", identifier);
		return (T) query.getSingleResult();//
//		return entityManager.find(clazz, identifier);
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> loadAll(Class<T> clazz) {
		return entityManager.createQuery("select from " + clazz.getName())
				.getResultList();
	}

	public <T> T getByNamedQuery(String queryName, Map<String, Object> queryParams) {
		List<T> result = findByNamedQuery(queryName, 1, queryParams);
		if (result.isEmpty()) {
			return null;
		}
		return result.get(0);
	}

	public <T> List<T> findByNamedQuery(String queryName, int limit,
			Map<String, Object> queryParams) {
		return findRangeByNamedQuery(queryName, limit, queryParams, 0);
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> findRangeByNamedQuery(String queryName, int limit,
			Map<String, Object> queryParams, int start) {
		Query query = entityManager.createNamedQuery(queryName);
		query.setFirstResult(start);
		query.setMaxResults(limit);
		Iterator<String> keys = queryParams.keySet().iterator();
		while (keys.hasNext()) {
			String key = keys.next();
			query.setParameter(key, queryParams.get(key));
		}
		return query.getResultList();
	}
	
	public int updateByNamedQuery(String queryName, Map<String, Object> queryParams) {
		Query query = entityManager.createNamedQuery(queryName);
		Iterator<String> keys = queryParams.keySet().iterator();
		while (keys.hasNext()) {
			String key = keys.next();
			query.setParameter(key, queryParams.get(key));
		}
		return query.executeUpdate();
	}

	public Query createQuery(String ql) {
		return entityManager.createQuery(ql);
	}
}
